#region Copyright (c) 2006-2010 Widgetsphere LLC, All Rights Reserved
//--------------------------------------------------------------------- *
//                          Widgetsphere  LLC                           *
//             Copyright (c) 2006-2010 All Rights reserved              *
//                                                                      *
//                                                                      *
//This file and its contents are protected by United States and         *
//International copyright laws.  Unauthorized reproduction and/or       *
//distribution of all or any portion of the code contained herein       *
//is strictly prohibited and will result in severe civil and criminal   *
//penalties.  Any violations of this copyright will be prosecuted       *
//to the fullest extent possible under law.                             *
//                                                                      *
//THE SOURCE CODE CONTAINED HEREIN AND IN RELATED FILES IS PROVIDED     *
//TO THE REGISTERED DEVELOPER FOR THE PURPOSES OF EDUCATION AND         *
//TROUBLESHOOTING. UNDER NO CIRCUMSTANCES MAY ANY PORTION OF THE SOURCE *
//CODE BE DISTRIBUTED, DISCLOSED OR OTHERWISE MADE AVAILABLE TO ANY     *
//THIRD PARTY WITHOUT THE EXPRESS WRITTEN CONSENT OF WIDGETSPHERE LLC   *
//                                                                      *
//UNDER NO CIRCUMSTANCES MAY THE SOURCE CODE BE USED IN WHOLE OR IN     *
//PART, AS THE BASIS FOR CREATING A PRODUCT THAT PROVIDES THE SAME, OR  *
//SUBSTANTIALLY THE SAME, FUNCTIONALITY AS ANY WIDGETSPHERE PRODUCT.    *
//                                                                      *
//THE REGISTERED DEVELOPER ACKNOWLEDGES THAT THIS SOURCE CODE           *
//CONTAINS VALUABLE AND PROPRIETARY TRADE SECRETS OF WIDGETSPHERE,      *
//INC.  THE REGISTERED DEVELOPER AGREES TO EXPEND EVERY EFFORT TO       *
//INSURE ITS CONFIDENTIALITY.                                           *
//                                                                      *
//THE END USER LICENSE AGREEMENT (EULA) ACCOMPANYING THE PRODUCT        *
//PERMITS THE REGISTERED DEVELOPER TO REDISTRIBUTE THE PRODUCT IN       *
//EXECUTABLE FORM ONLY IN SUPPORT OF APPLICATIONS WRITTEN USING         *
//THE PRODUCT.  IT DOES NOT PROVIDE ANY RIGHTS REGARDING THE            *
//SOURCE CODE CONTAINED HEREIN.                                         *
//                                                                      *
//THIS COPYRIGHT NOTICE MAY NOT BE REMOVED FROM THIS FILE.              *
//--------------------------------------------------------------------- *
#endregion
using System;
using System.Xml;
using System.Collections;
using System.ComponentModel;
using Widgetsphere.Generator.Common.GeneratorFramework;
using Widgetsphere.Generator.Common.Util;
using System.Collections.Generic;

namespace Widgetsphere.Generator.Models
{
  public class TableCollection : BaseModelCollection, IEnumerable<Table>
	{
		#region Member Variables

		protected Hashtable innerList = null;
		protected int lastId = 1;

		#endregion

		#region Constructor

    public TableCollection(IModelObject root)
      : base(root)
		{
			innerList = new Hashtable();
		}

		#endregion

		#region IXMLable Members
		public override void XmlAppend(XmlNode node)
		{
      try
      {
        XmlDocument oDoc = node.OwnerDocument;

        XmlAttribute keyNode = oDoc.CreateAttribute("key");
        keyNode.Value = this.Key.ToString();
        node.Attributes.Append(keyNode);

        foreach(Table table in innerList.Values)
        {
          XmlNode tableNode = oDoc.CreateElement("table");
          table.XmlAppend(tableNode);
          node.AppendChild(tableNode);
        }

      }
      catch(Exception ex)
      {
        throw;
      }
	
		}

		public override void XmlLoad(XmlNode node)
    {
			try
			{
				_key = XmlHelper.GetAttributeValue(node, "key", _key);
				XmlNodeList tableNodes = node.SelectNodes("table");
				foreach (XmlNode tableNode in tableNodes)
				{
					Table newTable = new Table(this.Root);
					newTable.XmlLoad(tableNode);
					if (lastId < newTable.Id)
						lastId = newTable.Id;
					innerList.Add(newTable.Id, newTable);
				}

				//Now run the postload operations
				foreach (Table t in this)
				{
					t.PostLoad();
				}

				//Remove relationships in error
				foreach (Table t in this)
				{
					List<Reference> delRefList = new List<Reference>();
					foreach (Reference r in t.Relationships)
					{
						if (r.Object == null) delRefList.Add(r);
						else if (((Relation)r.Object).ParentTableRef.Object != t)
							delRefList.Add(r);
						else System.Diagnostics.Debug.Write("");
					}

					//Perform actual remove
					foreach (Reference r in delRefList)
					{
						((ModelRoot)this.Root).Database.Relations.Remove((Relation)r.Object);
					}

				}

				//Remove relationships from tables that do not belong there
				foreach (Table t in this)
				{
					List<Reference> delRefList = new List<Reference>();
					foreach (Reference r in t.Relationships)
					{
						if (r.Object == null)
						{
							delRefList.Add(r);
						}
						else if (((Relation)r.Object).ParentTableRef.Object == t)
						{
							System.Diagnostics.Debug.Write("");
						}
						else if (((Relation)r.Object).ChildTableRef.Object == t)
						{
							System.Diagnostics.Debug.Write("");
						}
						else
						{
							delRefList.Add(r);
						}
					}

					//Perform actual remove
					foreach (Reference r in delRefList)
					{
						((ModelRoot)this.Root).Database.Relations.Remove((Relation)r.Object);
					}

				}

				this.Dirty = false;
			}
			catch (Exception ex)
			{				
				throw;
			}

		}
		#endregion

		#region Property Implementations

		public ICollection Tables
		{
			get{return innerList.Values;}
		}

		public ICollection TableIds
		{
			get{return innerList.Keys;}
		}

		#endregion

		#region Methods

		///// <summary>
		///// This returns a list of all columns for all tables
		///// </summary>
		///// <returns></returns>
		//public IEnumerable<Column> GetAllColumns()
		//{
		//  List<Column> retval = new List<Column>();
		//  foreach (Table table in this)
		//  {
		//    retval.AddRange(table.GetColumnsFullHierarchy(true));
		//  }
		//  return retval;
		//}

		/// <summary>
		/// This returns a list of all components for all tables
		/// </summary>
		/// <returns></returns>
		public IEnumerable<TableComponent> GetAllComponents()
		{
			List<TableComponent> retval = new List<TableComponent>();
			foreach (Table table in this)
			{
				retval.AddRange(table.GetTableComponentsFullHierarchy(true));
			}
			return retval;
		}

		public Table[] GetById(int id)
		{
			ArrayList retval = new ArrayList();
			foreach(Table element in this)
			{
				if (element.Id == id)
					retval.Add(element);
			}
			return (Table[])retval.ToArray(typeof(Table));
		}

		public Table[] GetByKey(string key)
		{
			ArrayList retval = new ArrayList();
			foreach (Table element in this)
			{
				if (element.Key == key)
					retval.Add(element);
			}
			return (Table[])retval.ToArray(typeof(Table));
		}

		#endregion

		#region Helpers

		public Table CreateTable()
		{
			Table table = new Table(this.Root);
			lastId++;
			table.SetId(lastId);
			return table;
		}

		#endregion

		#region IEnumerable Members
		public override IEnumerator GetEnumerator()
		{
			List<Table> al = new List<Table>();
			foreach(int key in innerList.Keys)
				al.Add((Table)innerList[key]);
			return al.GetEnumerator();
		}
		#endregion

		#region IDictionary Members
		public bool IsReadOnly
		{
			get
			{
				return innerList.IsReadOnly;
			}
		}

    public Table this[int tableId]
    {
      get { return (Table)innerList[tableId]; }
    }

    public Table this[string name]
    {
      get
      {
        foreach (Table element in this)
        {
          if (string.Compare(name, element.Name, true) == 0)
            return element;
        }
        return null;
      }
    }
    
    public void Remove(int tableId)
		{
			try
			{
				Table table = this.GetById(tableId)[0];

				//Remove all unit test dependencies
				foreach (Table t in this)
				{
					if (t.UnitTestDependencies.Contains(table))
						t.UnitTestDependencies.Remove(table);
				}

				ArrayList deleteList = new ArrayList();
				foreach (Relation relation in ((ModelRoot)this.Root).Database.Relations)
				{
					if (relation.ParentTableRef.Object == null)
						deleteList.Add(relation);
					else if (relation.ChildTableRef.Object == null)
						deleteList.Add(relation);
					else if ((relation.ParentTableRef.Object.Key == table.Key) || (relation.ChildTableRef.Object.Key == table.Key))
						deleteList.Add(relation);
				}

				foreach (Relation relation in deleteList)
					((ModelRoot)this.Root).Database.Relations.Remove(relation);

				//Remove actual columns
				for (int ii = 0; ii < table.Columns.Count; ii++)
				{
					((ModelRoot)this.Root).Database.Columns.Remove(((Column)table.Columns[ii].Object).Id);
				}
				//Remove column references
				table.Columns.Clear();

				this.Root.Dirty = true;
				innerList.Remove(tableId);

			}
			catch (Exception ex)
			{				
				throw;
			}
		}

		public void RemoveRange(IEnumerable<Table> removeList)
		{
			foreach (Table t in removeList)
				this.Remove(t);
		}

    public void Remove(Table table)
    {
      this.Remove(table.Id);
    }

		public bool Contains(int tableId)
		{
			return innerList.Contains(tableId);
		}

    public override void Clear()
		{
			innerList.Clear();
		}


		internal Table Add(Table value)
		{
			innerList.Add(value.Id, value);
			return value;
		}

		public Table Add(string name)
		{
			Table newItem = new Table(this.Root);
			newItem.Name = name;
			lastId++;
			newItem.SetId(lastId);
			this.Add(newItem);
			return newItem;
		}

    public override void AddRange(ICollection list)
    {
      foreach (Table element in list)
      {
        lastId++;
        element.SetId(lastId);
        innerList.Add(lastId, element);
      }
    }

		public Table Add()
		{
			return this.Add(this.GetUniqueName());
		}

    public bool IsFixedSize
    {
      get { return innerList.IsFixedSize; }
    }

		public bool Contains(string name)
		{
			foreach(Table table in this)
			{
				if (string.Compare(table.Name, name, true) == 0)
				{
					return true;
				}
			}
			return false;
		}

		protected internal string GetUniqueName()
		{
			//const string baseName = "Table";
			//int ii = 1;
			//string newName = baseName + ii.ToString();
			//while (this.Contains(newName))
			//{
			//  ii++;
			//  newName = baseName + ii.ToString();
			//}
			//return newName;
			return "[New Table]";
		}

		public IEnumerable<Column> GetAllColumns()
		{
			List<Column> retval = new List<Column>();
			foreach (Table t in this)
			{
				foreach (Reference r in t.Columns)
				{
					retval.Add((Column)r.Object);
				}
			}
			return retval;
		}

		#endregion

		#region ICollection Members

    public override bool IsSynchronized
		{
			get
			{
				return innerList.IsSynchronized;
			}
		}

		public override int Count
		{
			get
			{
				return innerList.Count;
			}
		}

    public override void CopyTo(Array array, int index)
		{
			innerList.CopyTo(array, index);
		}

    public override object SyncRoot
		{
			get
			{
				return innerList.SyncRoot;
			}
		}

		#endregion
		
		#region IEnumerable<Table> Members

		IEnumerator<Table> IEnumerable<Table>.GetEnumerator()
		{
			List<Table> al = new List<Table>();
			foreach (int key in innerList.Keys)
				al.Add((Table)innerList[key]);
			return al.GetEnumerator();
		}

		#endregion

		#region IEnumerable Members

		IEnumerator IEnumerable.GetEnumerator()
		{
			return this.GetEnumerator();
		}

		#endregion
	}
}
